home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / comm / term / term34Source.lha / termSaveWindow.c < prev    next >
C/C++ Source or Header  |  1993-07-16  |  14KB  |  681 lines

  1. /*
  2. **    termSaveWindow.c
  3. **
  4. **    Support routines for saving IFF-ILBM files
  5. **
  6. **    Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Current compression mode. */
  13.  
  14. #define DUMP        0
  15. #define RUN        1
  16.  
  17.     /* ByteRun compression data. */
  18.  
  19. #define MINRUN        3
  20. #define MAXRUN        128
  21. #define MAXDAT        128
  22.  
  23.     /* Chunk types. */
  24.  
  25. #define ID_ILBM        MAKE_ID('I','L','B','M')
  26. #define ID_ANNO        MAKE_ID('A','N','N','O')
  27. #define ID_BMHD        MAKE_ID('B','M','H','D')
  28. #define ID_CMAP        MAKE_ID('C','M','A','P')
  29. #define ID_CAMG        MAKE_ID('C','A','M','G')
  30. #define ID_BODY        MAKE_ID('B','O','D','Y')
  31.  
  32.     /* Masking technique. */
  33.  
  34. #define mskNone        0
  35.  
  36.     /* Compression techniques. */
  37.  
  38. #define cmpNone        0
  39. #define cmpByteRun1    1
  40.  
  41.     /* A bitmap header. */
  42.  
  43. typedef struct
  44. {
  45.     UWORD        w,h;            /* raster width & height in pixels */
  46.     WORD        x,y;            /* position for this image */
  47.     UBYTE        nPlanes;        /* # source bitplanes */
  48.     UBYTE        masking;        /* masking technique */
  49.     UBYTE        compression;        /* compression algorithm */
  50.     UBYTE        pad1;            /* UNUSED.  For consistency, put 0 here.*/
  51.     UWORD        transparentColor;    /* transparent "color number" */
  52.     UBYTE        xAspect,yAspect;    /* aspect ratio, a rational number x/y */
  53.     WORD        pageWidth,pageHeight;    /* source "page" size in pixels */
  54. } BitMapHeader;
  55.  
  56.     /* A single 8-bit colour register. */
  57.  
  58. typedef struct
  59. {
  60.     UBYTE        red,            /* red component, 0..255 */
  61.             green,            /* green component, 0..255 */
  62.             blue;            /* blue component, 0..255 */
  63. } ColorRegister;
  64.  
  65.     /* Local packer data. */
  66.  
  67. STATIC LONG        PackedBytes;
  68. STATIC BYTE        Buffer[MAXDAT + 1];
  69.  
  70.     /* PutDump(register PLANEPTR Destination,register LONG Count):
  71.      *
  72.      *    Output a byte dump.
  73.      */
  74.  
  75. STATIC PLANEPTR __regargs
  76. PutDump(register PLANEPTR Destination,register LONG Count)
  77. {
  78.     register PLANEPTR Source = Buffer;
  79.  
  80.     *Destination++     = Count - 1;
  81.      PackedBytes    += Count + 1;
  82.  
  83.     while(Count--)
  84.         *Destination++ = *Source++;
  85.  
  86.     return(Destination);
  87. }
  88.  
  89.     /* PutRun(register PLANEPTR Destination,LONG Count,WORD Char):
  90.      *
  91.      *    Output a byte run.
  92.      */
  93.  
  94. STATIC PLANEPTR __regargs
  95. PutRun(register PLANEPTR Destination,LONG Count,WORD Char)
  96. {
  97.     *Destination++     = -(Count - 1);
  98.     *Destination++     = Char;
  99.      PackedBytes    += 2;
  100.  
  101.     return(Destination);
  102. }
  103.  
  104.     /* PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize):
  105.      *
  106.      *    Pack a row of bitmap data using ByteRun compression,
  107.      *    based on the original "EA IFF 85" pack.c example code.
  108.      */
  109.  
  110. STATIC LONG __regargs
  111. PackRow(PLANEPTR *SourcePtr,register PLANEPTR Destination,LONG RowSize)
  112. {
  113.     register PLANEPTR Source = *SourcePtr;
  114.  
  115.     WORD    Buffered    = 1,
  116.         RunStart    = 0;
  117.     BYTE    Mode        = DUMP,
  118.         LastChar,
  119.         Char;
  120.  
  121.     PackedBytes = 0;
  122.  
  123.     Buffer[0] = LastChar = Char = *Source++;
  124.  
  125.     RowSize--;
  126.  
  127.     while(RowSize--)
  128.     {
  129.         Buffer[Buffered++] = Char = *Source++;
  130.  
  131.         if(Mode)
  132.         {
  133.             if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
  134.             {
  135.                 Destination    = PutRun(Destination,Buffered - 1 - RunStart,LastChar);
  136.                 Buffer[0]    = Char;
  137.                 Buffered    = 1;
  138.                 RunStart    = 0;
  139.                 Mode        = DUMP;
  140.             }
  141.         }
  142.         else
  143.         {
  144.             if(Buffered > MAXDAT)
  145.             {
  146.                 Destination    = PutDump(Destination,Buffered - 1);
  147.                 Buffer[0]    = Char;
  148.                 Buffered    = 1;
  149.                 RunStart    = 0;
  150.             }
  151.             else
  152.             {
  153.                 if(Char == LastChar)
  154.                 {
  155.                     if(Buffered - RunStart >= MINRUN)
  156.                     {
  157.                         if(RunStart)
  158.                             Destination = PutDump(Destination,RunStart);
  159.  
  160.                         Mode = RUN;
  161.                     }
  162.                     else
  163.                     {
  164.                         if(!RunStart)
  165.                             Mode = RUN;
  166.                     }
  167.                 }
  168.                 else
  169.                     RunStart = Buffered - 1;
  170.             }
  171.         }
  172.  
  173.         LastChar = Char;
  174.     }
  175.  
  176.     if(Mode)
  177.         PutRun(Destination,Buffered - RunStart,LastChar);
  178.     else
  179.         PutDump(Destination,Buffered);
  180.  
  181.     *SourcePtr = Source;
  182.  
  183.     return(PackedBytes);
  184. }
  185.  
  186.     /* PutANNO(struct IFFHandle *Handle):
  187.      *
  188.      *    Output `ANNO' chunk.
  189.      */
  190.  
  191. STATIC BYTE __regargs
  192. PutANNO(struct IFFHandle *Handle)
  193. {
  194.     extern    UBYTE    VersTag[];
  195.         WORD    Len;
  196.  
  197.     Len = strlen(&VersTag[1]);
  198.  
  199.         /* Push the `ANNO' chunk on the stack. */
  200.  
  201.     if(!PushChunk(Handle,0,ID_ANNO,Len))
  202.     {
  203.             /* Write the creator string. */
  204.  
  205.         if(WriteChunkBytes(Handle,&VersTag[1],Len) == Len)
  206.         {
  207.                 /* Pop the `ANNO' chunk. */
  208.  
  209.             if(!PopChunk(Handle))
  210.                 return(TRUE);
  211.         }
  212.     }
  213.  
  214.     return(FALSE);
  215. }
  216.  
  217.     /* PutBMHD():
  218.      *
  219.      *    Output `BMHD' chunk.
  220.      */
  221.  
  222. STATIC BYTE __regargs
  223. PutBMHD(struct IFFHandle *Handle,struct Window *Window,UBYTE Compression,LONG Left,LONG Top,LONG Width,LONG Height)
  224. {
  225.     struct DisplayInfo DisplayInfo;
  226.  
  227.         /* Get the display aspect ratio. */
  228.  
  229.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,GetVPModeID(&Window -> WScreen -> ViewPort)))
  230.     {
  231.         BitMapHeader Header;
  232.  
  233.             /* Fill in the bitmap header. */
  234.  
  235.         Header . w            = Width;
  236.         Header . h            = Height;
  237.         Header . pageWidth        = Window -> WScreen -> Width;
  238.         Header . pageHeight        = Window -> WScreen -> Height;
  239.         Header . x            = Left;
  240.         Header . y            = Top;
  241.         Header . nPlanes        = Window -> WScreen -> RastPort . BitMap -> Depth;
  242.         Header . masking        = mskNone;
  243.         Header . compression        = Compression;
  244.         Header . pad1            = 0;
  245.         Header . transparentColor    = 0;
  246.         Header . xAspect        = DisplayInfo . Resolution . x;
  247.         Header . yAspect        = DisplayInfo . Resolution . y;
  248.  
  249.             /* Push the `BMHD' chunk on the stack. */
  250.  
  251.         if(!PushChunk(Handle,0,ID_BMHD,sizeof(BitMapHeader)))
  252.         {
  253.                 /* Write the bitmap header. */
  254.  
  255.             if(WriteChunkBytes(Handle,&Header,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
  256.             {
  257.                     /* Pop the `BMHD' chunk. */
  258.  
  259.                 if(!PopChunk(Handle))
  260.                     return(TRUE);
  261.             }
  262.         }
  263.     }
  264.  
  265.     return(FALSE);
  266. }
  267.  
  268.     /* PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort):
  269.      *
  270.      *    Output `CMAP' chunk, only 4-bit colour registers
  271.      *    are supported so far.
  272.      */
  273.  
  274. STATIC BYTE __regargs
  275. PutCMAP(struct IFFHandle *Handle,struct ViewPort *VPort)
  276. {
  277.         /* Push the `CMAP' chunk on the stack. */
  278.  
  279.     if(!PushChunk(Handle,0,ID_CMAP,3 * VPort -> ColorMap -> Count))
  280.     {
  281.         ColorRegister    Colour;
  282.         LONG        i;
  283.         ULONG        Value,
  284.                 R,G,B;
  285.  
  286.             /* Read and convert all the
  287.              * ColorMap entries (4 bit colour
  288.              * components only).
  289.              */
  290.  
  291.         for(i = 0 ; i < VPort -> ColorMap -> Count ; i++)
  292.         {
  293.                 /* Read colour value. */
  294.  
  295.             Value = GetRGB4(VPort -> ColorMap,i);
  296.  
  297.                 /* Split the value into components. */
  298.  
  299.             R = (Value >> 8) & 0xF;
  300.             G = (Value >> 4) & 0xF;
  301.             B = (Value     ) & 0xF;
  302.  
  303.                 /* Store the colour components. */
  304.  
  305.             Colour . red    = (R << 4) | R;
  306.             Colour . green    = (G << 4) | G;
  307.             Colour . blue    = (B << 4) | B;
  308.  
  309.                 /* Write the colours. */
  310.  
  311.             if(WriteChunkBytes(Handle,&Colour,3) != 3)
  312.                 return(FALSE);
  313.         }
  314.  
  315.             /* Pop the `CMAP' chunk. */
  316.  
  317.         if(!PopChunk(Handle))
  318.             return(TRUE);
  319.     }
  320.  
  321.     return(FALSE);
  322. }
  323.  
  324.     /* PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort):
  325.      *
  326.      *    Output `CAMG' chunk.
  327.      */
  328.  
  329. STATIC BYTE __regargs
  330. PutCAMG(struct IFFHandle *Handle,struct ViewPort *VPort)
  331. {
  332.     if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
  333.     {
  334.         ULONG ViewModes = GetVPModeID(VPort);
  335.  
  336.         if(WriteChunkBytes(Handle,&ViewModes,sizeof(ULONG)) == sizeof(ULONG))
  337.         {
  338.             if(!PopChunk(Handle))
  339.                 return(TRUE);
  340.         }
  341.     }
  342.  
  343.     return(FALSE);
  344. }
  345.  
  346.     /* PutBODY(struct IFFHandle *Handle)
  347.      *
  348.      *    Output `BODY' chunk.
  349.      */
  350.  
  351. STATIC BYTE __regargs
  352. PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap,UBYTE Compression)
  353. {
  354.     BYTE         Success = FALSE;
  355.     PLANEPTR    *Planes;
  356.  
  357.         /* Allocate temporary bitplane pointers. */
  358.  
  359.     if(Planes = (PLANEPTR *)AllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR))
  360.     {
  361.         register LONG i;
  362.  
  363.             /* Copy the bitplane pointers. */
  364.  
  365.         for(i = 0 ; i < BitMap -> Depth ; i++)
  366.             Planes[i] = BitMap -> Planes[i];
  367.  
  368.             /* Are we to compress the data? */
  369.  
  370.         if(Compression == cmpByteRun1)
  371.         {
  372.             PLANEPTR PackBuffer;
  373.  
  374.                 /* Allocate line compression buffer. */
  375.  
  376.             if(PackBuffer = (PLANEPTR)AllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY))
  377.             {
  378.                     /* Push the `BODY' chunk on the stack. */
  379.  
  380.                 if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  381.                 {
  382.                     register LONG    PackedBytes,
  383.                             j;
  384.  
  385.                         /* So far, we are quite successful,
  386.                          * any write access to fail will
  387.                          * cause `Success' to drop to FALSE.
  388.                          */
  389.  
  390.                     Success = TRUE;
  391.  
  392.                         /* Compress all the rows. */
  393.  
  394.                     for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  395.                     {
  396.                             /* Compress all the planes. */
  397.  
  398.                         for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  399.                         {
  400.                                 /* Do the compression. */
  401.  
  402.                             PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
  403.  
  404.                                 /* Write the compressed data. */
  405.  
  406.                             if(WriteChunkBytes(Handle,PackBuffer,PackedBytes) != PackedBytes)
  407.                                 Success = FALSE;
  408.                         }
  409.                     }
  410.  
  411.                         /* Pop the `BODY' chunk. */
  412.  
  413.                     if(PopChunk(Handle))
  414.                         Success = FALSE;
  415.                 }
  416.  
  417.                     /* Free the line compression buffer. */
  418.  
  419.                 FreeVec(PackBuffer);
  420.             }
  421.         }
  422.         else
  423.         {
  424.                 /* Push the `BODY' chunk on the stack. */
  425.  
  426.             if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  427.             {
  428.                 register LONG j;
  429.  
  430.                     /* So far, we are quite successful,
  431.                      * any write access to fail will
  432.                      * cause `Success' to drop to FALSE.
  433.                      */
  434.  
  435.                 Success = TRUE;
  436.  
  437.                     /* Compress all the rows. */
  438.  
  439.                 for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  440.                 {
  441.                         /* Compress all the planes. */
  442.  
  443.                     for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  444.                     {
  445.                             /* Write the row. */
  446.  
  447.                         if(WriteChunkBytes(Handle,Planes[j],BitMap -> BytesPerRow) != BitMap -> BytesPerRow)
  448.                             Success = FALSE;
  449.                         else
  450.                             Planes[j] += BitMap -> BytesPerRow;
  451.                     }
  452.                 }
  453.  
  454.                     /* Pop the `BODY' chunk. */
  455.  
  456.                 if(PopChunk(Handle))
  457.                     Success = FALSE;
  458.             }
  459.         }
  460.  
  461.             /* Free the temporary bitplane pointers. */
  462.  
  463.         FreeVec(Planes);
  464.     }
  465.  
  466.         /* Return the result. */
  467.  
  468.     return(Success);
  469. }
  470.  
  471.     /* SaveWindow(STRPTR Name,struct Window *Window):
  472.      *
  473.      *    Save the contents of a window to a file.
  474.      */
  475.  
  476. BYTE
  477. SaveWindow(STRPTR Name,struct Window *Window)
  478. {
  479.     struct RastPort        *RPort;
  480.     BYTE             Success    = FALSE,
  481.                  NewFile    = FALSE,
  482.                  Locked        = TRUE;
  483.  
  484.     LockLayerRom(Window -> RPort -> Layer);
  485.  
  486.         /* Allocate a dummy rastport, we will need only
  487.          * to copy the contents of the window into the
  488.          * bitmap.
  489.          */
  490.  
  491.     if(RPort = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
  492.     {
  493.         struct BitMap *BitMap;
  494.  
  495.             /* Initialize the rastport with defaults. */
  496.  
  497.         InitRastPort(RPort);
  498.  
  499.             /* Allocate a bitmap. */
  500.  
  501.         if(BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY))
  502.         {
  503.             LONG    Width    = Window -> Width    - (Window -> BorderLeft + Window -> BorderRight),
  504.                 Height    = Window -> Height    - (Window -> BorderTop + Window -> BorderBottom),
  505.                 Left    = Window -> LeftEdge + Window -> BorderLeft,
  506.                 Top    = Window -> TopEdge + Window -> BorderTop;
  507.             WORD    i;
  508.  
  509.                 /* Put it into the rastport. */
  510.  
  511.             RPort -> BitMap = BitMap;
  512.  
  513.                 /* Initialize it with the window dimensions. */
  514.  
  515.             InitBitMap(BitMap,Window -> WScreen -> RastPort . BitMap -> Depth,Width,Height);
  516.  
  517.                 /* Flag success so any allocation
  518.                  * to fail in the bitplane allocation
  519.                  * loop will indicate failure.
  520.                  */
  521.  
  522.             Success = TRUE;
  523.  
  524.                 /* Allocate all the bitplanes necessary. */
  525.  
  526.             for(i = 0 ; Success && i < BitMap -> Depth ; i++)
  527.             {
  528.                 if(!(BitMap -> Planes[i] = AllocRaster(Width,Height)))
  529.                     Success = FALSE;
  530.             }
  531.  
  532.                 /* Did we get all the planes we wanted? */
  533.  
  534.             if(Success)
  535.             {
  536.                 struct IFFHandle *Handle;
  537.  
  538.                     /* Copy the window contents to the
  539.                      * local bitmap.
  540.                      */
  541.  
  542.                 ClipBlit(Window -> RPort,Window -> BorderLeft,Window -> BorderTop,RPort,0,0,Width,Height,MINTERM_COPY);
  543.  
  544.                     /* Release the lock on the window layer. */
  545.  
  546.                 UnlockLayerRom(Window -> RPort -> Layer);
  547.  
  548.                 Locked = FALSE;
  549.  
  550.                     /* Reset the success indicator. */
  551.  
  552.                 Success = FALSE;
  553.  
  554.                     /* Allocate an iff handle. */
  555.  
  556.                 if(Handle = AllocIFF())
  557.                 {
  558.                         /* Open a file for write access. */
  559.  
  560.                     if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
  561.                     {
  562.                             /* Remember that we succeeded
  563.                              * in creating a new file.
  564.                              */
  565.  
  566.                         NewFile = TRUE;
  567.  
  568.                             /* Tell iffparse.library that it's
  569.                              * a plain AmigaDOS file handle.
  570.                              */
  571.  
  572.                         InitIFFasDOS(Handle);
  573.  
  574.                             /* Open the file for writing. */
  575.  
  576.                         if(!OpenIFF(Handle,IFFF_WRITE))
  577.                         {
  578.                                 /* Push parent chunk on the
  579.                                  * stack.
  580.                                  */
  581.  
  582.                             if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
  583.                             {
  584.                                     /* Output all the chunk data. */
  585.  
  586.                                 if(PutANNO(Handle))
  587.                                 {
  588.                                     UBYTE Compression;
  589.  
  590.                                         /* Don't compress the bitmap if
  591.                                          * isn't really worth it.
  592.                                          */
  593.  
  594.                                     if(BitMap -> BytesPerRow > 4)
  595.                                         Compression = cmpByteRun1;
  596.                                     else
  597.                                         Compression = cmpNone;
  598.  
  599.                                     if(PutBMHD(Handle,Window,Compression,Left,Top,Width,Height))
  600.                                     {
  601.                                         if(PutCMAP(Handle,&Window -> WScreen -> ViewPort))
  602.                                         {
  603.                                             if(PutCAMG(Handle,&Window -> WScreen -> ViewPort))
  604.                                             {
  605.                                                 if(PutBODY(Handle,BitMap,Compression))
  606.                                                 {
  607.                                                         /* Pop the parent chunk
  608.                                                          * from the stack.
  609.                                                          */
  610.  
  611.                                                     if(!PopChunk(Handle))
  612.                                                         Success = TRUE;
  613.                                                 }
  614.                                             }
  615.                                         }
  616.                                     }
  617.                                 }
  618.                             }
  619.  
  620.                                 /* Close the iff handle. */
  621.  
  622.                             CloseIFF(Handle);
  623.                         }
  624.  
  625.                             /* Close the file. */
  626.  
  627.                         if(!Close(Handle -> iff_Stream))
  628.                             Success = FALSE;
  629.                     }
  630.  
  631.                         /* Free the iff handle. */
  632.  
  633.                     FreeIFF(Handle);
  634.                 }
  635.             }
  636.  
  637.                 /* Free all bitplanes. */
  638.  
  639.             for(i = 0 ; i < BitMap -> Depth ; i++)
  640.             {
  641.                 if(BitMap -> Planes[i])
  642.                     FreeRaster(BitMap -> Planes[i],Width,Height);
  643.             }
  644.  
  645.                 /* Free the bitmap. */
  646.  
  647.             FreeVec(BitMap);
  648.         }
  649.  
  650.             /* Free the rastport. */
  651.  
  652.         FreeVec(RPort);
  653.     }
  654.  
  655.         /* Release the window layer in case it is still locked. */
  656.  
  657.     if(Locked)
  658.         UnlockLayerRom(Window -> RPort -> Layer);
  659.  
  660.         /* If successful, clear the `executable' bit. */
  661.  
  662.     if(Success)
  663.     {
  664.         AddProtection(Name,FIBF_EXECUTE);
  665.  
  666.         if(Config -> MiscConfig -> CreateIcons)
  667.             AddIcon(CaptureName,FILETYPE_PICTURE,TRUE);
  668.     }
  669.     else
  670.     {
  671.             /* Delete the remains of the file. */
  672.  
  673.         if(NewFile)
  674.             DeleteFile(Name);
  675.     }
  676.  
  677.         /* Return the result. */
  678.  
  679.     return(Success);
  680. }
  681.